import cv2
import numpy as np
from paddleocr import PaddleOCR
from typing import Tuple, List, Optional
import os
import logging
from app.config import config

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class MediaProcessor:
    def __init__(self):
        # 初始化人脸检测器
        logger.info("正在加载人脸检测模型...")
        if not os.path.exists(config.FACE_CASCADE_PATH):
            raise FileNotFoundError(f"人脸检测模型文件不存在: {config.FACE_CASCADE_PATH}")
        
        self.face_cascade = cv2.CascadeClassifier(config.FACE_CASCADE_PATH)
        if self.face_cascade.empty():
            raise ValueError("无法加载人脸检测模型")
        
        # 延迟初始化OCR
        self.ocr = None
        logger.info("处理器初始化完成")
    
    def _init_ocr(self):
        """延迟初始化OCR"""
        if self.ocr is None:
            logger.info("正在初始化PaddleOCR...")
            try:
                self.ocr = PaddleOCR(**config.OCR_CONFIG)
                logger.info("PaddleOCR初始化成功")
            except Exception as e:
                logger.error(f"PaddleOCR初始化失败: {e}")
                raise
    
    def detect_faces(self, image: np.ndarray) -> List[Tuple[int, int, int, int]]:
        """检测图像中的人脸"""
        try:
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            faces = self.face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30),
                flags=cv2.CASCADE_SCALE_IMAGE
            )
            return faces.tolist() if faces is not None else []
        except Exception as e:
            logger.error(f"人脸检测失败: {e}")
            return []
    
    def detect_license_plates(self, image: np.ndarray) -> List[Tuple[int, int, int, int]]:
        """检测图像中的车牌"""
        try:
            self._init_ocr()
            result = self.ocr.ocr(image, cls=False)
            
            plates = []
            if result and result[0]:
                for line in result[0]:
                    if line and line[1][0]:  # 确保有识别结果
                        box = line[0]
                        x_coords = [int(p[0]) for p in box]
                        y_coords = [int(p[1]) for p in box]
                        x, y = min(x_coords), min(y_coords)
                        w, h = max(x_coords) - x, max(y_coords) - y
                        plates.append((x, y, w, h))
            return plates
        except Exception as e:
            logger.error(f"车牌检测失败: {e}")
            return []
    
    def blur_regions(self, image: np.ndarray, regions: List[Tuple[int, int, int, int]], blur_strength: int = 121) -> np.ndarray:
        """模糊指定区域"""
        try:
            blurred = image.copy()
            for (x, y, w, h) in regions:
                roi = blurred[y:y+h, x:x+w]
                # 高斯模糊
                roi = cv2.GaussianBlur(roi, (blur_strength, blur_strength), 0)
                blurred[y:y+h, x:x+w] = roi
            return blurred
        except Exception as e:
            logger.error(f"模糊处理失败: {e}")
            return image
    
    def process_image(self, input_path: str, output_path: str) -> str:
        """处理单张图片"""
        # 确保路径是字符串并且正确处理Windows路径
        input_path = str(input_path).replace('/', '\\')
        output_path = str(output_path).replace('/', '\\')

        
        try:
            logger.info(f"正在处理图片: {input_path}")
            image = cv2.imread(input_path)
            if image is None:
                raise ValueError("无法读取图像文件")
            
            # 检测人脸和车牌
            faces = self.detect_faces(image)
            plates = self.detect_license_plates(image)
            logger.info(f"检测到 {len(faces)} 张人脸和 {len(plates)} 个车牌")
            
            # 模糊处理
            if faces or plates:
                image = self.blur_regions(image, faces + plates)
            
            cv2.imwrite(output_path, image)
            logger.info(f"图片处理完成，保存到: {output_path}")
            return output_path
        except Exception as e:
            logger.error(f"图片处理失败: {e}")
            raise
    
    def process_video(self, input_path: str, output_path: str) -> str:
        """处理视频文件"""
        try:
            # 确保路径是字符串并且正确处理Windows路径
            input_path = str(input_path).replace('/', '\\')
            output_path = str(output_path).replace('/', '\\')

            logger.info(f"正在处理视频: {input_path}")
            cap = cv2.VideoCapture(input_path)
            if not cap.isOpened():
                raise ValueError("无法打开视频文件")
            
            # 获取视频属性
            frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            fps = cap.get(cv2.CAP_PROP_FPS)
            total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            
            # 创建视频写入器 (使用MP4V编解码器)
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
            
            frame_count = 0
            try:
                while True:
                    ret, frame = cap.read()
                    if not ret:
                        break
                    
                    # 每10帧记录一次进度
                    if frame_count % 10 == 0:
                        logger.info(f"处理进度: {frame_count}/{total_frames} 帧")
                    
                    # 检测人脸和车牌
                    faces = self.detect_faces(frame)
                    plates = self.detect_license_plates(frame)
                    
                    # 模糊处理
                    if faces or plates:
                        frame = self.blur_regions(frame, faces + plates)
                    
                    out.write(frame)
                    frame_count += 1
            finally:
                cap.release()
                out.release()
            
            logger.info(f"视频处理完成，保存到: {output_path}")
            return output_path
        except Exception as e:
            logger.error(f"视频处理失败: {e}")
            raise

# 全局处理器实例
processor = MediaProcessor()